# coding: utf-8
# Author: legend
# @Time： 2020/8/27 下午10:05
from fastapi import HTTPException
from starlette.authentication import AuthenticationBackend
from starlette.status import HTTP_400_BAD_REQUEST
from tortoise.exceptions import DoesNotExist

import settings
from apps.iacs.models import User
from utils.redis import Redis


class NoAuthentication(AuthenticationBackend):
    async def authenticate(self, request):
        pass


class RedisTokenAuthentication(AuthenticationBackend):
    keyword = 'Token'
    model = User

    async def authenticate(self, request):
        if "Authorization" not in request.headers:
            return
        if 'login' in str(request.url):
            return None
        auth = request.headers["Authorization"]
        return await self.authenticate_credentials(auth.split()[1])

    def get_model(self):
        """
        ### 父类中的方法，这里不需要。
        :return:
        """
        pass

    async def authenticate_credentials(self, token):
        """
        重写父类方法，通过redis来实现认证。
        :param token:
        :return:
        """
        redis_key = settings.REDIS_LOGIN_TOKEN_KEY.format(token=token)
        async with Redis() as redis:
            user_id = await redis.hget(redis_key, 'id')
        try:
            user_id = int(user_id)
        except Exception:
            raise HTTPException(HTTP_400_BAD_REQUEST, 'Invalid token')
        try:
            user = await self.model.get(pk=user_id)
            user.authenticate()
        except DoesNotExist:
            raise HTTPException(HTTP_400_BAD_REQUEST, 'Invalid token')

        if not user.is_active:
            raise HTTPException(HTTP_400_BAD_REQUEST, 'User is inactive.')
        return token, user
